#include <stdio.h>
#include <string.h>
#include "DBOption/Redis/RedisResult.h"
#include "base/core/com_define.h"
#include "base/core/char_operation.h"

#ifndef WIN32
  #define _atoi64(val) strtoll(val, nullptr, 10)
#endif

RedisResult::RedisResult(redisReply* reply) 
	: m_reply(nullptr) 
{
    SetRedisResult(reply);
};

RedisResult::~RedisResult() 
{}

bool RedisResult::SetRedisResult(redisReply* reply) 
{
    Release();
    m_reply = reply;

    if (reply != nullptr && IsError() && m_reply->str != nullptr) 
	{
        LogErrFmtPrint("[common] redis error : %s", m_reply->str);
    }
    return true;
}

bool RedisResult::Release() 
{
    if (m_reply != nullptr) 
	{
        freeReplyObject(m_reply);
        m_reply = nullptr;
    }
    return true;
}

bool RedisResult::IsNil() 
{
    MMO_ASSERT(m_reply != nullptr);
    if (m_reply && m_reply->type == REDIS_REPLY_NIL) 
	{
        return true;
    }
    return false;
}

bool RedisResult::IsString() 
{
    MMO_ASSERT(m_reply != nullptr);

    if (m_reply && m_reply->type == REDIS_REPLY_STRING) 
	{
        return true;
    }
    return false;
}

bool RedisResult::IsStatus() 
{
    MMO_ASSERT(m_reply != nullptr);
    if (m_reply && m_reply->type == REDIS_REPLY_STATUS) 
	{
        return true;
    }
    return false;
}

bool RedisResult::IsInteger() 
{
    MMO_ASSERT(m_reply != nullptr);

    if (m_reply && m_reply->type == REDIS_REPLY_INTEGER) 
	{
        return true;
    }
    return false;
}

bool RedisResult::IsArray() 
{
    MMO_ASSERT(m_reply != nullptr);
    if (m_reply && m_reply->type == REDIS_REPLY_ARRAY) 
	{
        return true;
    }
    return false;
}

bool RedisResult::IsError() 
{
    MMO_ASSERT(m_reply != nullptr);
    if (m_reply && m_reply->type == REDIS_REPLY_ERROR) 
	{
        return true;
    }
    return false;
}

bool RedisResult::IsStatusOK() 
{
    MMO_ASSERT(m_reply != nullptr);
    if (!IsStatus()) 
	{
        return false;
    }
#ifdef  _MSC_VER
    if (_stricmp(m_reply->str, "OK") != 0) 
	{
        return false;
    }
#else
    if (strcasecmp(m_reply->str, "OK") != 0) 
	{
        return false;
    }
#endif
    return true;
}

bool RedisResult::GetStatus(char* str, uint32_t strLength) 
{
    bool result  = false;
    bool retCode = false;

    MMOLOG_ASSERT_EXIT(m_reply != nullptr);
    MMOLOG_PROCESS_ERROR(m_reply->type == REDIS_REPLY_STATUS);
    MMOLOG_PROCESS_ERROR(strLength > (uint32_t)m_reply->len);
    retCode = SafeCopyString(str, strLength, m_reply->str);
    MMOLOG_PROCESS_ERROR(retCode);
    result = true;
Exit0:
    return result;
}

bool RedisResult::GetInteger(int64_t& value) 
{
    bool result = false;
    MMOLOG_ASSERT_EXIT(m_reply != nullptr);
    MMOLOG_PROCESS_ERROR(m_reply->type == REDIS_REPLY_INTEGER);
    value = m_reply->integer;
    result = true;
Exit0:
    return result;
}

bool RedisResult::GetNumber(int64_t& value) 
{
    bool result = false;
    bool retCode = false;

    char str[32] = {0};
    uint32_t length = 0;
    retCode = GetString(str, 32, length);
    MMOLOG_PROCESS_ERROR(retCode && length < countof(str));
    value = static_cast<int64_t>(strtoull(str, nullptr, 10));
    result = true;
Exit0:
    return result;
}

bool RedisResult::GetString(char* str, uint32_t strLength, uint32_t& length) 
{
    bool result = false;

    MMOLOG_ASSERT_EXIT(str != nullptr);
    MMOLOG_ASSERT_EXIT(strLength > 0);
    MMOLOG_ASSERT_EXIT(m_reply != nullptr);
    MMOLOG_PROCESS_ERROR(m_reply->type == REDIS_REPLY_STRING);
    length = m_reply->len;
    MMOLOG_PROCESS_ERROR(strLength > length);
    memcpy(str, m_reply->str, length);
    str[length] = '\0';
    result = true;
Exit0:
    return result;
}

bool RedisResult::GetBinary(char* buf, uint32_t bufLength, uint32_t& length) 
{
    bool result = false;

    MMOLOG_ASSERT_EXIT(buf != nullptr);
    MMOLOG_ASSERT_EXIT(bufLength > 0);
    MMOLOG_ASSERT_EXIT(m_reply != nullptr);
    MMOLOG_PROCESS_ERROR(m_reply->type == REDIS_REPLY_STRING);
    length = m_reply->len;
    MMOLOG_PROCESS_ERROR(bufLength >= length);
    memcpy(buf, m_reply->str, length);
    result = true;
Exit0:
    return result;
}

bool RedisResult::GetStringLength(uint32_t& length) 
{
    bool result = false;
    MMOLOG_ASSERT_EXIT(m_reply != nullptr);
    MMOLOG_PROCESS_ERROR(m_reply->type == REDIS_REPLY_STRING);
    length = m_reply->len;
    result = true;
Exit0:
    return result;
}

bool RedisResult::GetBinaryLength(uint32_t& length) 
{
    bool result = false;
    MMOLOG_ASSERT_EXIT(m_reply != nullptr);
    MMOLOG_PROCESS_ERROR(m_reply->type == REDIS_REPLY_STRING);
    length = m_reply->len;
    result = true;
Exit0:
    return result;
}

bool RedisResult::GetStringArray(std::vector<std::string>& vec_str) 
{
    bool result = false;
    int count = 0;

    MMOLOG_ASSERT_EXIT(m_reply != nullptr);
    MMOLOG_PROCESS_ERROR(m_reply->type == REDIS_REPLY_ARRAY);
    for (unsigned index = 0; index < m_reply->elements; ++index) 
	{
        redisReply* element_reply = m_reply->element[index];
        if (element_reply->type == REDIS_REPLY_STRING) 
		{
            vec_str.push_back(element_reply->str);
            ++count;
        }
        else 
		{
            vec_str.push_back("nil");
        }
    }
    result = true;
Exit0:
    return result;
}

bool RedisResult::GetBinaryArray(std::vector<std::string>& vec_str) 
{
    bool result = false;
    int count = 0;

    MMOLOG_ASSERT_EXIT(m_reply != nullptr);
    MMOLOG_PROCESS_ERROR(m_reply->type == REDIS_REPLY_ARRAY);
    for (unsigned index = 0; index < m_reply->elements; ++index) 
	{
        redisReply* element_reply = m_reply->element[index];
        if (element_reply->type == REDIS_REPLY_STRING) 
		{
            std::string str(element_reply->str, element_reply->len);
            vec_str.push_back(str);
            ++count;
        }
        else 
		{
            vec_str.push_back("nil");
        }
    }
    result = true;
Exit0:
    return result;
}
